import { LitElement, html, css } from 'lit';

import { customElement, property } from 'lit/decorators.js';
import {
  Graph,
  RubberBandHandler,
  constants
} from '@maxgraph/core';

//AI编辑指南：
// * 不要使用constants.*
// * 不要使用getModel, 使用getDataModel
// fontSize必须指定为数字，不能使用fontSize: '12'这种字符串形式
// 调整标题位置，只需要调整verticalAlign，不需要设置labelPosition

interface Layer {
  name: string;
  modules?: Module[];
}

interface Module {
  name: string;
  features?: Feature[];
}

interface Feature {
  name: string;
  subFeatures?: SubFeature[];
}

interface SubFeature {
  name: string;
}

@customElement('software-model-graph')
export class SoftwareModelGraph extends LitElement {
  private graph!: Graph;
  private container!: HTMLElement;

  @property({ type: Array })
  layers: Layer[] = [
    {
      name: 'Presentation',
      modules: [
        { name: 'User Interface' },
        { name: 'Navigation' }
      ]
    },
    {
      name: 'Business',
      modules: [
        { name: 'Data Processing' },
        { name: 'Validation' }
      ]
    },
    {
      name: 'Data',
      modules: [
        { name: 'Database Access' },
        { name: 'Data Storage' }
      ]
    }]

  static styles = css`
    :host {
      display: block;
      height: 100%;
    }
    .graph-container {
      height: 100%;
      width: 100%;
      background: white;
    }
    .toolbar {
      padding: 10px;
      background: #f5f5f5;
      display: flex;
      gap: 10px;
    }
    select, button {
      padding: 8px 12px;
    }
  `;

  private get root() {
    return this.graph.getDataModel();
  }

  render() {
    return html`
      <div class="toolbar">
      <select id="layer-select">
          ${this.layers.map((layer, index) => html`<option value="${index}">${layer.name}</option>`)}
        </select>
        <button @click=${this.addModule}>Add Module</button>
        <button @click=${this.addFeature}>Add Feature</button>
      </div>
      <div class="graph-container" id="graph-container"></div>
    `;
  }

  firstUpdated() {
    this.container = this.shadowRoot?.getElementById('graph-container') as HTMLElement;
    this.initGraph();
    this.renderLayers();
  }

  private initGraph() {
    this.graph = new Graph(this.container);
    this.graph.setPanning(true);
    new RubberBandHandler(this.graph);
    this.graph.setConnectable(false); // 默认不连线
  }
  private renderLayers() {
    const parent = this.graph.getDefaultParent();
    const layerHeight = 120;
    const startY = 20;

    this.layers.forEach((layer, i) => {
      const y = startY + i * (layerHeight + 20);

      const layerCell = this.graph.insertVertex({
        parent, value: layer.name,
        position: [20, y + 20],
        id: `layer-${i}`,
        size: [this.container.clientWidth - 40, layerHeight],
        style: {
          fillColor: '#E1F5FE',
          strokeColor: '#0288D1',
          fontColor: '#01579B',
          fontSize: 16,
          fontStyle: 1,
          // verticalLabelPosition: 'top',
          verticalAlign: 'top',
          align: 'center',
          spacingTop: 10
        }
      });

      layer.modules?.forEach((module, j) => {
        this.addModuleToLayer(i, layerCell, module, j);
      });
    });
  }

  private addModuleToLayer(layerI: number, layerCell: any, module: Module, index: number) {
    const layerWidth = this.container.clientWidth - 40;
    const moduleHeight = 60;
    const vSpacing = 30;
    const modulesPerRow = this.layers[layerI].modules?.length || 1;
    const moduleWidth = (layerWidth - 40) / modulesPerRow; // 平分宽度，留出20px边距
    const hSpacing = 10; // 减少水平间距

    const row = 0; // 所有模块在一行
    const col = index;

    const x = 20 + col * moduleWidth;
    const y = 40 + row * (moduleHeight + vSpacing);

    var cell = this.root.getCell(`module-${layerI}-${index}`);

    if (cell) {
      cell.value = module.name;
      var newGeo = cell.getGeometry()?.clone();
      newGeo!.x = x;
      newGeo!.y = y;
      newGeo!.width = moduleWidth - hSpacing;
      newGeo!.height = moduleHeight;
      this.root.setGeometry(cell, newGeo);
    } else {
      this.graph.insertVertex({
        parent: layerCell,
        value: module.name,
        position: [x, y],
        id: `module-${layerI}-${index}`,
        size: [moduleWidth - hSpacing, moduleHeight], // 减去间距保持美观
        style: {
          fillColor: '#E8F5E9',
          strokeColor: '#81C784',
          fontColor: '#2E7D32',
          fontSize: 12,
          verticalAlign: 'middle',
          align: 'center'
        }
      });
    }


  }

  private relayoutModules(layerId: number) {
    const layerCell = this.root.getCell(`layer-${layerId}`);
    if (!layerCell) return;
    // 重新添加所有模块
    this.layers[layerId].modules?.forEach((module, index) => {
      this.addModuleToLayer(layerId, layerCell, module, index);
    });
  }

  private addModule() {
    const select = this.shadowRoot?.getElementById('layer-select') as HTMLSelectElement;
    const layerId = Number(select.value);
    const moduleName = prompt('Enter module name:');
    let layer = this.layers[layerId];

    if (moduleName) {
      let module = { name: moduleName };
      layer.modules = [...(layer.modules || []), module];
      const model = this.graph.getDataModel();
      const layerCell = model.getCell(`layer-${layerId}`)
      if (layerCell) {
        model.beginUpdate();
        this.relayoutModules(layerId);
        model.endUpdate();
      }
    }
  }
  private addFeature() {
    const moduleName = prompt('Enter module name to add feature:');
    if (!moduleName) return;

    const featureName = prompt('Enter feature name:');
    if (!featureName) return;

    const model = this.graph.getDataModel();
    model.beginUpdate();
    try {
      const cells = Object.values(model.cells);
      const moduleCell = cells.find(cell =>
        cell.value === moduleName && cell.style?.fillColor === '#E8F5E9'
      );

      if (moduleCell) {
        // 添加feature
        const feature = this.graph.insertVertex({
          parent: moduleCell,
          value: featureName,
          position: [20, 40],
          size: [100, 30],
          style: {
            fillColor: '#FFECB3',
            strokeColor: '#FFA000',
            fontColor: '#E65100',
            fontSize: 12,
            shape: "rectangle",
            rounded: true,
            gradientColor: '#FFE082',
            gradientDirection: "south"
          }
        });

        // 计算所有feature需要的总高度
        const features = this.graph.getChildCells(moduleCell).filter(cell => cell !== feature);
        const featureHeight = 30;
        const spacing = 10;

        // 调整父模块大小
        const moduleGeo = moduleCell.getGeometry()?.clone();
        if (moduleGeo) {
          moduleGeo.height = moduleGeo.height + featureHeight;
          this.graph.resizeCell(moduleCell, moduleGeo);
          // 添加feature后修改module cell样式使标题顶部显示
          this.graph.setCellStyle({
            ...moduleCell.getStyle(),
            verticalAlign: 'top',
            spacingTop: 5
          }, [moduleCell]);

          // 获取同层所有module
          const layerCell = moduleCell.getParent();
          const siblings = this.graph.getChildCells(layerCell).filter(cell => cell !== moduleCell);

          siblings.forEach((cell, index) => {
            const geo = cell.getGeometry()?.clone();
            if (geo) {
              geo.height = moduleGeo.height;
              this.graph.resizeCell(cell, geo);
            }
          });
        }

        //调整所在layer的高度
        const layerCell = moduleCell.getParent();
        if (layerCell) {
          const geo = layerCell.getGeometry()?.clone();
          if (geo) {
            geo.height += featureHeight;
            this.graph.resizeCell(layerCell, geo);
          }
        }

        // 调整后续层级的位置
        const currentLayerIndex = this.layers.findIndex(l => l.name === layerCell.value);
        if (currentLayerIndex >= 0) {
          const layersToAdjust = this.layers.slice(currentLayerIndex + 1);
          layersToAdjust.forEach((layer, i) => {
            const layerCellToAdjust = this.graph.getDataModel().getCell(`layer-${currentLayerIndex + i + 1}`);
            if (layerCellToAdjust) {
              const geo = layerCellToAdjust.getGeometry()?.clone();
              if (geo) {
                geo.y += featureHeight; // 增加间距避免重叠
                this.graph.resizeCell(layerCellToAdjust, geo, true);
              }
            }
          });
        }
      }
    } finally {
      model.endUpdate();
    }
  }


  public getModelData(): Layer[] {
    return this.layers;
  }

  public loadModelData(data: Layer[]) {
    this.layers = data;
    this.graph.clear();
    this.renderLayers();
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'software-model-graph': SoftwareModelGraph;
  }
}